#coding=utf-8
import re
from decimal import Decimal, DecimalException
from datetime import date,time

#like 2007-10-8
_datere = r'\d{4}-\d{1,2}-\d{1,2}'
#like 9:35:40, 9:1:1
_timere = r'\d{1,2}:\d{1,2}:\d{1,2}'

alnum_re = re.compile(r'^\w+$')
ansi_date_re = re.compile('^%s$' % _datere)
ansi_time_re = re.compile('^%s$' % _timere)
ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))

stcode_re = re.compile('^[06]\d{5}$')

class ValidationError(Exception):
    
    def __init__(self, data, msg=None):
        self.data = str(data)
        
        if msg:
            self.message = msg
        else:
            self.message = 'Failure in Validation.'
            
    
    def __str__(self):
        return "%s The wrong data is %s"%(self.message, self.data)

class NegativeTSError(Exception):
    def __init__(self, code):
        self.code = code
        
    def __str__(self):
        return "%s的流通A股数量<=0"%self.code
    
def isValidStcode(c):
    if not stcode_re.search(c):
        raise ValidationError(c)
    return True
    
def isValidDate(d):
    if not ansi_date_re.search(d):
        raise ValidationError(d)
    
    year, month, day = map(int, d.split('-'))
    try:
        dd = date(year, month, day)
    except ValueError, e:
        raise ValidationError(dd, 'Invalid date.')
    return True
    
def isValidExdate(i):
    isValidDate(i)   
    
    year, month, day = map(int, i.split('-'))
    d = date(year, month, day)
    if year < 1990:
        raise ValidationError(i, '中国股市始于1990年.')
    w = d.weekday()
    if w > 4:
        raise ValidationError(i, '周末是让人休息的 ;-) .')
        
    return True
              
def isValidTime(t):
    if not ansi_time_re.search(t):
        raise ValidationError(t)
    hour,minunte,second = map(int, t.split(':'))
    try:
        tt = time(hour, minunte, second)
    except ValueError,e:
        raise ValidationError(tt, 'Invalid time.')
    return True   
    
def isValidExTime(t):

    s1 = time(9, 29,0)
    e1 = time(11,31,0)
    s2 = time(12,59,0)
    e2 = time(15,1,0)
    
    isValidTime(t)
    hour,minunte,second = map(int, t.split(':'))
    tt = time(hour, minunte, second)
    
    if (tt>s1 and tt<e1) or (tt>s2 and tt<e2):
        return True
    
    raise ValidationError(tt, "中国股市交易时间: 9:29-11:31 and 12:59-15:01.")
    
class IsValidDecimal(object):

    def __init__(self, max_digits, decimal_places, msg=None):
        self.max_digits = max_digits
        self.decimal_places = decimal_places
        self.msg = msg

    def __call__(self, data):
        try:
            val = Decimal(data)
        except DecimalException:
            raise ValidationError(data, "%s. Please enter a valid decimal number."%self.msg)

        pieces = str(val).lstrip("-").split('.')
        decimals = (len(pieces) == 2) and len(pieces[1]) or 0
        digits = len(pieces[0])
        
        
        if digits + decimals > self.max_digits:
            raise ValidationError(data, "%s. Please enter a valid decimal number with at most %s total digit."%(self.msg,self.max_digits) )
                
        if digits > (self.max_digits - self.decimal_places):
            raise ValidationError(data, "%s. Please enter a valid decimal number with a whole part of at most %s digit."%(self.msg, str(self.max_digits-self.decimal_places)) )
                
        if decimals > self.decimal_places:
            raise ValidationError(data, "%s. Please enter a valid decimal number with at most %s decimal place."%(self.msg,self.decimal_places))
        
        return True
        
def isValidPricefromSina(pd):
    #validate price data from sina/历史交易
    #data格式: [日期,开盘价,最高价,收盘价,最低价,交易量(手),交易金额(万元)]
    date = pd[0]
    isValidExdate(date)
    
    error_msg = "invalid price data on %s"%date
    for p in pd[1:5]:
    
        if p < 0 or p[-1] != '0':
            raise ValidationError(p, error_msg)
        
        p = p[:-1]
        ivd = IsValidDecimal(8, 2, error_msg)
        ivd(p)
        
    #check 成交量，成交额
    for p in pd[5:]:
        if p <= 0:   
            raise ValidationError(p, error_msg)
    return True
    
def isValidDealfromSina(dd):
    #validate deal data from sina/成交明细
    #data格式: [时间,成交量,成交价,性质]
    
    et = dd[0]
    isValidExTime(et)
    
    s =','.join([str(i) for i in dd[1:]])
    error_msg = "invalid deal data(%s) on %s"%(s, et)
    if dd[1] < 0:
        raise ValidationError(dd[1], error_msg)
    
    p = dd[2]
    if p < 0 or p[-1] != '0':
        raise ValidationError(p, error_msg)
        
    p = p[:-1]
    ivd = IsValidDecimal(8, 2, error_msg)
    ivd(p)
    
    bs = dd[-1]
    if not bs in ['b','s','n']:
        raise ValidationError(bs, error_msg)
    return True
        
        
    
    
